home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / gnu / glibc108.gz / glibc108 / glibc-1.08.1 / stdio / __getdelim.c next >
C/C++ Source or Header  |  1992-03-30  |  4KB  |  171 lines

  1. /* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <stddef.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <limits.h>
  25.  
  26. /* Read up to (and including) a TERMINATOR from STREAM into *LINEPTR
  27.    (and null-terminate it). *LINEPTR is a pointer returned from malloc (or
  28.    NULL), pointing to *N characters of space.  It is realloc'd as
  29.    necessary.  Returns the number of characters read (not including the
  30.    null terminator), or -1 on error or EOF.  */
  31.  
  32. ssize_t
  33. DEFUN(__getdelim, (lineptr, n, terminator, stream),
  34.       char **lineptr AND size_t *n AND int terminator AND FILE *stream)
  35. {
  36.   char *line, *p;
  37.   size_t size, copy;
  38.  
  39.   if (!__validfp (stream) || lineptr == NULL || n == NULL)
  40.     {
  41.       errno = EINVAL;
  42.       return -1;
  43.     }
  44.  
  45.   if (ferror (stream))
  46.     return -1;
  47.  
  48.   /* Make sure we have a line buffer to start with.  */
  49.   if (*lineptr == NULL || *n < 2) /* !seen and no buf yet need 2 chars.  */
  50.     {
  51. #ifndef    MAX_CANON
  52. #define    MAX_CANON    256
  53. #endif
  54.       line = realloc (*lineptr, MAX_CANON);
  55.       if (line == NULL)
  56.     return -1;
  57.       *lineptr = line;
  58.       *n = MAX_CANON;
  59.     }
  60.  
  61.   line = *lineptr;
  62.   size = *n;
  63.  
  64.   copy = size;
  65.   p = line;
  66.  
  67.   if (stream->__buffer == NULL && stream->__userbuf)
  68.     {
  69.       /* Unbuffered stream.  Not much optimization to do.  */
  70.  
  71.       while (1)
  72.     {
  73.       size_t len;
  74.  
  75.       while (--copy > 0)
  76.         {
  77.           register int c = getc (stream);
  78.           if (c == EOF)
  79.         goto lose;
  80.           else if ((*p++ = c) == terminator)
  81.         goto win;
  82.         }
  83.  
  84.       /* Need to enlarge the line buffer.  */
  85.       len = p - line;
  86.       size *= 2;
  87.       line = realloc (line, size);
  88.       if (line == NULL)
  89.         goto lose;
  90.       *lineptr = line;
  91.       *n = size;
  92.       p = line + len;
  93.       copy = size - len;
  94.     }
  95.     }
  96.   else
  97.     {
  98.       /* Leave space for the terminating null.  */
  99.       --copy;
  100.  
  101.       if (!stream->__seen || stream->__buffer == NULL || stream->__pushed_back)
  102.     {
  103.       /* Do one with getc to allocate a buffer.  */
  104.       int c = getc (stream);
  105.       if (c == EOF)
  106.         goto lose;
  107.       *p++ = c;
  108.       if (c == terminator)
  109.         goto win;
  110.       --copy;
  111.     }
  112.  
  113.       while (1)
  114.     {
  115.       size_t i;
  116.       char *found;
  117.  
  118.       i = stream->__get_limit - stream->__bufp;    
  119.       if (i == 0)
  120.         {
  121.           /* Refill the buffer.  */
  122.           int c = __fillbf (stream);
  123.           if (c == EOF)
  124.         goto lose;
  125.           *p++ = c;
  126.           if (c == terminator)
  127.         goto win;
  128.           i = stream->__get_limit - stream->__bufp;    
  129.         }
  130.  
  131.       if (i > copy)
  132.         i = copy;
  133.  
  134.       found = (char *) __memccpy ((PTR) p, stream->__bufp, terminator, i);
  135.       if (found != NULL)
  136.         {
  137.           stream->__bufp += found - p;
  138.           p = found;
  139.           goto win;
  140.         }
  141.  
  142.       stream->__bufp += i;
  143.       p += i;
  144.       copy -= i;
  145.       if (copy == 0)
  146.         {
  147.           /* Need to enlarge the line buffer.  */
  148.           size_t len = p - line;
  149.           size *= 2;
  150.           line = realloc (line, size);
  151.           if (line == NULL)
  152.         goto lose;
  153.           *lineptr = line;
  154.           *n = size;
  155.           p = line + len;
  156.           copy = size - len;
  157.           /* Leave space for the terminating null.  */
  158.           --copy;
  159.         }
  160.     }
  161.     }
  162.  
  163.  lose:
  164.   if (p == *lineptr)
  165.     return -1;
  166.   /* Return a partial line since we got an error in the middle.  */
  167.  win:
  168.   *p = '\0';
  169.   return p - *lineptr;
  170. }
  171.